package org.simpleframework.core;

import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.simpleframework.core.annotation.Component;
import org.simpleframework.core.annotation.Controller;
import org.simpleframework.core.annotation.Repository;
import org.simpleframework.core.annotation.Service;
import org.simpleframework.util.ClassUtil;
import org.simpleframework.util.ValidationUtil;

import java.lang.annotation.Annotation;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @program: simpleframework
 * @description:
 * @author: lishuang
 * @create: 2021-11-23 16:29
 **/
@Slf4j
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class BeanContainer {

    /**
     * 存放所有目标对象的map
     */
    private final Map<Class<?>, Object> beanMap = new ConcurrentHashMap<>();

    /**
     * 加载bean的注解列表
     */
    private final List<Class<? extends Annotation>> BEAN_ANNOTATION =
            Arrays.asList(Controller.class, Service.class, Component.class, Repository.class);

    public static BeanContainer getInstance() {
        return ContainerHolder.HOLDER.instance;
    }

    private enum ContainerHolder {
        HOLDER;
        private BeanContainer instance;

        ContainerHolder() {
            instance = new BeanContainer();
        }
    }


    private boolean loaded = false;


    /**
     * 根据注解筛选出Bean的Class集合
     *
     * @param annotation
     * @return
     */
    public Set<Class<?>> getClassByAnnotation(Class<? extends Annotation> annotation) {
        //1 获取所有的class对象
        Set<Class<?>> classSet = beanMap.keySet();
        if (isEmptySet(classSet)) {
            return null;
        }
        //2.通过注解筛选被注解标记的class对象，并添加到classSet里
        Set<Class<?>> annotationSet = new HashSet<>();
        for (Class<?> clazz : classSet) {
            if (clazz.isAnnotationPresent(annotation)) {
                annotationSet.add(clazz);
            }
        }
        return annotationSet.size() == 0 ? null : annotationSet;
    }

    /**
     * 移除一个IOC容器管理的对象
     */
    public Object removeBean(Class<?> clazz) {
        return beanMap.remove(clazz);
    }

    /**
     * 根据Class对象获取Bean实例
     */
    public Object getBean(Class<?> clazz) {
        return beanMap.get(clazz);
    }

    /**
     * 获取容器管理的所有Class对象集合
     */
    public Set<Class<?>> getClasses() {
        return beanMap.keySet();
    }

    /**
     * 获取所有Bean集合
     */
    public Set<Object> getBeans() {
        return new HashSet<>(beanMap.values());
    }

    /**
     * 过接口或者父类获取实现类或者子类的Class集合，不包括其本身
     *
     * @param clazz
     * @return
     */
    public Set<Class<?>> getClassesBySuper(Class<?> clazz) {
        //1 获取所有的class对象
        Set<Class<?>> classSet = beanMap.keySet();
        if (isEmptySet(classSet)) {
            return null;
        }
        //2 判断keySet里的元素是否是传入的接口或者类的子类，如果是，就将其添加到classSet里
        Set<Class<?>> superSet = new HashSet<>();
        for (Class<?> cla : classSet) {
            if (clazz.isAssignableFrom(cla) && !clazz.equals(cla)) {
                // 判断keySet里的元素是否是传入的接口或者类的子类
                superSet.add(cla);
            }
        }
        return superSet.size() == 0 ? null : superSet;
    }

    /**
     * 判断beanMap 是否为空
     *
     * @param classSet
     * @return
     */
    public boolean isEmptySet(Set<Class<?>> classSet) {
        if (ValidationUtil.isEmpty(classSet)) {
            log.warn("BeanContainer is null");
            return true;
        }
        return false;
    }

    /**
     * 是否加载过bean
     *
     * @return
     */
    public boolean isLoaded() {
        return loaded;
    }

    /**
     * 获取bean的数量
     *
     * @return
     */
    public int size() {
        return beanMap.size();
    }

    /**
     * 加载所有的bean
     *
     * @param packageName
     */
    public synchronized void loadBeans(String packageName) {
        if (isLoaded()) {
            log.warn("BeanContainer has been loaded");
            return;
        }
        Set<Class<?>> classSet = ClassUtil.extractPackageClass(packageName);
        if (isEmptySet(classSet)) {
            log.warn("BeanContainer has been loaded");
            return;
        }
        for (Class<?> clazz : classSet) {
            for (Class<? extends Annotation> annotation : BEAN_ANNOTATION) {
                // 如果类上面标记了定义的注解
                if (clazz.isAnnotationPresent(annotation)) {
                    // 将目标类本身作为键，目标类的实例作为值，放入到beanMap中,定义一个newInstance方法用于通过反射初始化对象
                    beanMap.put(clazz, ClassUtil.newInstance(clazz, true));
                }
            }
        }
        loaded = true;
    }
}
